package sample;

import Entity.DownloadEntity;
import com.sun.webkit.dom.HTMLElementImpl;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.util.Duration;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.html.HTMLElement;
import Utils.*;

import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Controller implements Initializable {
    @FXML
    TextArea goodUrlsText;
    @FXML
    TextArea spiderResultText;
    @FXML
    TextArea downloadResultText;
    @FXML
    Button startDownloadBtn;
    @FXML
    TabPane mainTabPane;
    @FXML
    Tab configTab;
    @FXML
    ToggleGroup mathTimeGroup;
    @FXML
    ToggleGroup fieldGroup;
    @FXML
    ToggleGroup audienceGroup;


    Timeline doneDetectLine = null;
    LinkedBlockingDeque<DownloadEntity> downloadEntities = new LinkedBlockingDeque<>();
    ExecutorService service = null;

    public void onStartDownloadBtnClick() {
        downloadEntities.clear();
        String[] goodUrls = goodUrlsText.getText().split("\n");

        //每个一段时间启动一次爬虫
        //这样写也是无奈之举，框架限制
        Index index = new Index();
        Timeline shootTimeLine = new Timeline(new KeyFrame(Duration.seconds(3), event -> {
            int indexValue = index.getAndIncreaseIndex();
            getDownloadEntity(indexValue, goodUrls.length, goodUrls[indexValue], downloadEntities);
        }));
        shootTimeLine.setCycleCount(goodUrls.length);
        shootTimeLine.play();

        spiderResultText.appendText("总计" + goodUrls.length + "\t开始下载,大约五秒输出一次\n");

        mainTabPane.getSelectionModel().select(configTab);
        //写配置文件
        StringBuilder configSB = new StringBuilder();
        configSB.append("匹配时间=")
                .append(((RadioButton) mathTimeGroup.getSelectedToggle()).getText())
                .append("\r\n")
                .append("领域=")
                .append(((RadioButton) fieldGroup.getSelectedToggle()).getText())
                .append("\r\n")
                .append("人群=")
                .append(((RadioButton) audienceGroup.getSelectedToggle()).getText())
                .append("\r\n");
        File outputDir = new File("output");
        if (!outputDir.exists()) {
            outputDir.mkdirs();
        }
        FileUtil.writeFile(configSB.toString(), "output" + File.separator + "config.txt");
    }


    public static String getSuffix(String fullName) {
        return fullName.substring(fullName.lastIndexOf('.'), fullName.length());
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        //启动下载线程
        service = Executors.newFixedThreadPool(4);
        for (int i = 0; i < 4; i++) {
            service.execute(new DownloadWorker());
        }
        //初始化
        doneDetectLine = new Timeline(new KeyFrame(Duration.seconds(5), event -> {
            if (downloadEntities.size() == 0) {
                downloadPrompt("所有工作都已完成\n");
                spiderPrompt("所有工作都已完成");
                doneDetectLine.stop();
            }
        }));
        doneDetectLine.setCycleCount(20);
    }

    public void stop() {
        if (service != null) {
            service.shutdownNow();
        }
    }

    class DownloadWorker implements Runnable {
        @Override
        public void run() {
            //合理性检测
            if (downloadEntities == null) {
                return;
            }
            while (!Thread.interrupted()) {
                DownloadEntity entity = null;
                try {
                    entity = downloadEntities.take();
                } catch (InterruptedException e) {
                    //应用程序关闭时会调用Controller.stop()这其中会关闭线程池,
                    //所以 take可能会有InterruptException，对于这种情况
                    //不需要采取任何操作，直接返回就好了
                    return;
                }
                //创建必要文件夹
                String prefixPath = "output" + File.separator + entity.getId();
                File rootFile = new File(prefixPath);
                if (!rootFile.exists()) {
                    rootFile.mkdirs();
                }
                //构建写入info文件
                StringBuilder infoSB = new StringBuilder();
                infoSB.append("原始地址=")
                        .append(entity.getOriginUrl())
                        .append("\r\n")
                        .append("商品名=")
                        .append(entity.getGoodName())
                        .append("\r\n");
                FileUtil.writeFile(infoSB.toString(), prefixPath + File.separator + "info.txt");
                //确定视频的名字和 图片的名字
                String videoFileName = entity.getId() + getSuffix(entity.getVideoUrl());
                String videoFilePath = prefixPath + File.separator + videoFileName;
                String videoOutputFilePath = prefixPath + File.separator + "output" + getSuffix(entity.getVideoUrl());

                String posterFileName = entity.getId() + getSuffix(entity.getPostUrl());
                String posterFilePath = prefixPath + File.separator + posterFileName;
                //下载视频
                if (!HttpUtil.downloadFile(entity.getVideoUrl(), videoFilePath)) {
                    downloadPrompt(videoFileName + "\t\t下载失败\n");
                } else {
                    downloadPrompt(videoFileName + "\t\t下载成功,开始切割\n");
                    //下载成功 切割视频
                    String commandString = "ffmpeg -ss 00:00:00 -i " + videoFilePath + " -c copy -t 5 " + videoOutputFilePath;
                    try {
                        Runtime.getRuntime().exec(commandString);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                //下载图片
                if (!HttpUtil.downloadFile(entity.getPostUrl(), posterFilePath)) {
                    downloadPrompt(posterFileName + "\t\t下载失败\n");
                } else {
                    downloadPrompt(posterFileName + "\t\t下载成功\n");
                }
            }
        }


    }

    private void downloadPrompt(String message) {
        downloadResultText.appendText(message);
        downloadResultText.setScrollTop(Double.MAX_VALUE);
    }

    private String getIdFromUrl(String url) {
        Pattern r = Pattern.compile("[\\?|&]id=([0-9]+)");
        Matcher matcher = r.matcher(url);
        if (matcher.find()) {
            return matcher.group(1);
        } else {
            return "";
        }
    }

    private boolean hasBeenPublished(String id) {
        String resultString = HttpUtil.getUrlString("http://daren.qumai.org/xin7.php?iid=" + id);
        if (resultString.contains("该宝贝未投短视频") && resultString.contains("该宝贝符合营销7条")) {
            return true;
        }

        return false;
    }

    private void spiderPrompt(String message) {
//        System.out.println(message);
        if (message.indexOf(message.length() - 1) != '\n') {
            message += "\n";
        }
        spiderResultText.appendText(message);
        //滚动到最下面
        spiderResultText.setScrollTop(Double.MAX_VALUE);
    }

    private void getDownloadEntity(int index, int totalLen, String url, LinkedBlockingDeque<DownloadEntity> entities) {
        DownloadEntity resultEntity = new DownloadEntity();

        resultEntity.setId(getIdFromUrl(url));
        resultEntity.setOriginUrl(url);

//        //如果是最后一个商品，就启动doneDetectLine
//        if (index == totalLen - 1) {
//            doneDetectLine.play();
//        }
        //首先判断是淘宝还是天猫
        WebEngine engine = new WebView().getEngine();
        engine.load(url);
        Timeline clickTimeLine = new Timeline(new KeyFrame(Duration.seconds(4), event -> {
            Document document = engine.getDocument();
            if (document == null) {
                spiderPrompt(index + "\t" + resultEntity.getId() + "\tdocument为空");
                return;
            }
            //判断是否有视频
            if (document.getElementsByTagName("video").getLength() == 0) {//无视频
                spiderPrompt(index + "\t" + resultEntity.getId() + "\t该商品无视频");
                return;
            }
            //商品包含视频
            //判断是否商品已经被添加过了
            if (hasBeenPublished(resultEntity.getId())) {//添加过了
                spiderPrompt(index + "\t" + resultEntity.getId() + "\t该商品已经被添加过了");
                return;
            }
            //获取商品标题
            NodeList h3s = document.getElementsByTagName("h3");
            for (int i = 0; i < h3s.getLength(); i++) {
                HTMLElement element = (HTMLElement) h3s.item(i);
                String classAttribute = element.getAttribute("class");
                if (classAttribute != null && classAttribute.equals("tb-main-title")) {
                    String goodName = element.getTextContent().trim();
                    goodName = goodName.substring(0, goodName.length() - 2);
                    resultEntity.setGoodName(goodName);
                    break;
                }
            }

            if (url.contains("item.taobao.com")) {
                //找到播放视频按钮
                NodeList buttons = document.getElementsByTagName("button");
                int size = buttons.getLength();
                HTMLElementImpl button = null;
                for (int i = 0; i < size; i++) {
                    button = (HTMLElementImpl) buttons.item(i);
                    if (button.getAttribute("class").equals("vjs-center-start vjs-button")) {
                        break;
                    }
                }
                if (button == null) {
                    spiderPrompt(index + "\t" + resultEntity.getId() + "\t没有获取到button");

                } else {
                    //点击按钮
                    button.click();

                    Timeline getSrcTimeLine = new Timeline(new KeyFrame(Duration.millis(400), event1 -> {
                        HTMLElement video = (HTMLElement) document.getElementsByTagName("video").item(0);
                        //获取到了想要的所有信息
                        resultEntity.setPostUrl("http:" + video.getAttribute("poster"));
                        resultEntity.setVideoUrl("http:" + video.getAttribute("src"));

                        spiderPrompt(index + "\t" + resultEntity.getVideoUrl());
                        try {
                            entities.put(resultEntity);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }));
                    getSrcTimeLine.setCycleCount(1);
                    getSrcTimeLine.play();
                }
            } else if (url.contains("detail.tmall.com")) {
//                HTMLElement video = (HTMLElement) document.getElementsByTagName("video").item(0);
//                //获取到了想要的所有信息
//                resultEntity.setPostUrl("http:" + video.getAttribute("poster"));
//                resultEntity.setVideoUrl("http:" + video.getAttribute("src"));
//
//                spiderPrompt(index + "\t" + resultEntity.getVideoUrl());
//                try {
//                    entities.put(resultEntity);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
            }

        }));
        clickTimeLine.setCycleCount(1);
        clickTimeLine.play();
    }

}

class Index {
    private int index = 0;

    int getAndIncreaseIndex() {
        int result = index;
        index++;
        return result;
    }

    int getIndex() {
        return index;
    }
}
